#ifndef _TBSTRING_H_
#define _TBSTRING_H_

#include "TBSettings.h"

#define TB_STRING_QT
#define TB_STRING_STL

#ifdef _WIN32
	#define TB_STRING_SAFE
#endif

#ifdef TB_STRING_SAFE

	#define TB_STRCPY(dst, maximum, src)          strcpy_s(dst, maximum, src)
	#define TB_STRNCPY(dst, maximum, src, len)    strncpy_s(dst, maximum, src, len)
	#define TB_STRCAT(dst, maximum, src)          strcat_s(dst, maximum, src)
	#define TB_STRNCAT(dst, maximum, src, len)    strncat_s(dst, maximum, src, len)
	#define TB_SSCANF(src, format, ...)           sscanf_s(src, format, __VA_ARGS__)
	#define TB_SPRINTF(dst, maximum, format, ...) sprintf_s(dst, maximum, format, __VA_ARGS__)

	#define TB_MBSTOWCS(dst, maximum, src, count) mbstowcs_s(NULL, dst, maximum, src, count)

#else

	#define TB_STRCPY(dst, maximum, src)          strcpy(dst, src)
	#define TB_STRNCPY(dst, maximum, src, len)    strncpy(dst, src, len)
	#define TB_STRCAT(dst, maximum, src)          strcat(dst, src)
	#define TB_STRNCAT(dst, maximum, src, len)    strncat(dst, src, len)
	#define TB_SSCANF(src, format, ...)           sscanf(src, format, __VA_ARGS__)
	#define TB_SPRINTF(dst, maximum, format, ...) sprintf(dst, format, __VA_ARGS__)

	#define TB_MBSTOWCS(dst, maximum, src, count) mbstowcs(dst, src, count)

#endif

namespace tb
{

	class TB_DLL_FUNC StringOld
	{

		struct ArgList;
	
	public:
	
		StringOld();
		StringOld(int a_Maximum);
		StringOld(const char* a_String);
		StringOld(const char* a_String, int a_Maximum);
		StringOld(const wchar_t* a_String);
		StringOld(const wchar_t* a_String, int a_Maximum);
		StringOld(const StringOld& a_String);
		StringOld(const StringOld& a_String, int a_Maximum);
		~StringOld();

		StringOld& Arg(short a_Number);
		StringOld& Arg(unsigned short a_Number);
		StringOld& Arg(long a_Number);
		StringOld& Arg(unsigned long a_Number);
		StringOld& Arg(int a_Number);
		StringOld& Arg(unsigned int a_Number);
		StringOld& Arg(float a_Number, int a_Precision = -1);
		StringOld& Arg(double a_Number, int a_Precision = -1);
		StringOld& Arg(const char* a_String);
		StringOld& Arg(const wchar_t* a_String);
		StringOld& Arg(StringOld& a_String);

		// ================================
		// Operators
		// ================================

		bool operator ! ();

		operator char* ();
		operator wchar_t* ();

		StringOld& operator = (const char* a_String);
		StringOld& operator = (StringOld a_String);

		StringOld operator + (const char* a_String);
		StringOld operator + (StringOld& a_String);

		StringOld& operator += (const char* a_String);
		StringOld& operator += (const wchar_t* a_String);
		StringOld& operator += (StringOld& a_String);

		bool operator == (const char* a_String);
		bool operator == (const wchar_t* a_String);
		bool operator == (StringOld& a_String);

		// ================================
		// Iterators
		// ================================

		typedef char* iterator;
		iterator Begin();
		iterator End();
		iterator operator [] (int a_Index);

		char At(int a_Index);

		// ================================
		// Functions
		// ================================

		bool IsEmpty();

		StringOld Middle(int a_Begin, int a_Length = -1);
		StringOld Left(int a_Length = -1);
		StringOld Right(int a_Length = -1);

		int FindRight(char a_Char);
		int FindLeft(char a_Char);

		bool BeginsWith(StringOld a_String);
		bool EndsWith(StringOld a_String);
		bool Equals(StringOld& a_String);

		/*
			Returns a string with padding. 
			
			If a_Truncate is set to false and a_Length is smaller than the length of the string, the whole string is returned.
			If a_Truncate is set to false and a_Length is greater than the length of the string, the string with padding (a_Padding) is returned.
			If a_Truncate is set to true and a_Length is smaller than the length of the string, a_Length characters of the string is returned.
			If a_Truncate is set to true and a_Length is greater than the length of the string, the string with padding (a_Padding) is returned.
		*/
		StringOld LeftJustified(int a_Length, char a_Padding = ' ', bool a_Truncate = false);

		bool Clear();
		bool Resize(int a_Maximum = -1);

		StringOld& Append(const char* a_String);
		StringOld& Append(const wchar_t* a_String);
		StringOld& Append(const StringOld& a_String);
		StringOld& Prepend(const char* a_String);
		StringOld& Prepend(const wchar_t* a_String);
		StringOld& Prepend(const StringOld& a_String);

		const char* GetBytes() const { return m_Data; }
		int GetLength() const;
		int GetMaxLength() { return m_Maximum; }
		int GetWidth() const;

		short ToShort(bool* a_Check = 0);
		unsigned short ToUShort(bool* a_Check = 0);
		long ToLong(bool* a_Check = 0);
		unsigned long ToULong(bool* a_Check = 0);
		long long ToLongLong(bool* a_Check = 0);
		unsigned long long ToULongLong(bool* a_Check = 0);
		float ToFloat(bool* a_Check = 0);
		double ToDouble(bool* a_Check = 0);

	private:

		char* m_Data;
		int m_Length, m_Maximum, m_Size, m_Width;
		ArgList* m_ArgList;

		StringOld& (StringOld::*_Append)(const StringOld&);
		StringOld& _AppendFix(const StringOld& a_String);
		StringOld& _AppendDyn(const StringOld& a_String);

		StringOld& (StringOld::*_Prepend)(const StringOld&);
		StringOld& _PrependFix(const StringOld& a_String);
		StringOld& _PrependDyn(const StringOld& a_String);

		void _ArgList();
		StringOld& _ArgHelper(const char* a_Middle, int a_Length, int a_Width = 1);
		StringOld& _ArgHelperWide(const wchar_t* a_Middle, int a_Length);
	
	}; // class String

}; // namespace tb
	
#endif